package com.zlyx.easy.netty.server.core;

import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.Map;

import com.zlyx.easy.core.handler.IHandler;
import com.zlyx.easy.core.hex.Hex;
import com.zlyx.easy.core.loggers.Logger;
import com.zlyx.easy.core.utils.ByteUtils;
import com.zlyx.easy.core.utils.JsonUtils;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;

/**
 * 
 * @Auth 赵光
 * @Describle 抽象netty服务端
 * @2019年1月25日 下午2:45:23
 */
@Sharable
public abstract class AbstractNettyServer<T> extends ChannelInboundHandlerAdapter implements IHandler<T> {

	private Class<T> tClass = getTClass(this.getClass());

	protected ChannelHandlerContext ctx;

	/**
	 * 读数据
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try {
			byte[] bytes = (byte[]) msg;
			T data = null;
			if (bytes != null) {
				this.ctx = ctx;
				if (Hex.class == tClass) {
					data = (T) Hex.newHex(ByteUtils.bytesToHexString(bytes));
				} else if (byte[].class == tClass) {
					data = (T) bytes;
				} else if (Map.class == tClass) {
					data = (T) JsonUtils.fromJson(new String(bytes), Map.class);
				} else {
					data = (T) new String(bytes);
				}
				write(doHandle(data));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			ReferenceCountUtil.release(msg);
		}
	}

	public void write(T msg) throws Exception {
		if (msg != null) {
			if (Hex.class == tClass) {
				this.writeBytes(ByteUtils.hexStringToByte(((Hex) msg).getHex()));
			} else if (byte[].class == tClass) {
				this.writeBytes((byte[]) msg);
			} else if (Map.class == tClass) {
				this.writeBytes(msg.toString().getBytes());
			} else if (String.class == tClass) {
				this.writeBytes(((String) msg).getBytes());
			} else if (Object.class == tClass) {
				this.writeBytes(msg.toString().getBytes());
			} else {
				this.writeBytes(((String) msg).getBytes());
			}
		}
	}

	public void writeBytes(byte[] bytes) throws Exception {
		if (bytes != null) {
			Logger.info(this.getClass(), Arrays.toString(bytes));
			Channel channel = ctx.channel();
			channel.writeAndFlush(bytes);
		}
	}

	/**
	 * 没有事件活跃时,主动关闭通道
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent e = (IdleStateEvent) evt;
			if (e.state() == IdleState.READER_IDLE) {
				ctx.close();
			}
		}
	}

	/**
	 * 异常处理
	 */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {
		e.printStackTrace();
		ctx.close();
	}

	/**
	 * 处理消息
	 * 
	 * @return
	 * @throws Exception
	 */
	@Override
	public abstract T doHandle(T msg) throws Exception;

	@SuppressWarnings("unchecked")
	public Class<T> getTClass(Class<?> tClass) {
		if (tClass.getGenericSuperclass().getTypeName().contains("<")) {
			return (Class<T>) ((ParameterizedType) tClass.getGenericSuperclass()).getActualTypeArguments()[0];
		} else if (tClass != Object.class) {
			return getTClass(tClass.getSuperclass());
		}
		return null;
	}

	/**
	 * 代码控制是否开启(优先级大于@NettyServer注解)
	 * 
	 * @return
	 */
	public boolean isOpen() {
		return true;
	}
}
